{
  "cells": [
    {
      "metadata": {
        "id": "DhWmZgAVwDGu",
        "colab_type": "text"
      },
      "cell_type": "markdown",
      "source": [
        "Copyright 2021 Google LLC\n",
        "\n",
        "Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "you may not use this file except in compliance with the License.\n",
        "You may obtain a copy of the License at\n",
        "\n",
        "    https://www.apache.org/licenses/LICENSE-2.0\n",
        "\n",
        "Unless required by applicable law or agreed to in writing, software\n",
        "distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "See the License for the specific language governing permissions and\n",
        "limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "aY9ia0-D7xWb"
      },
      "source": [
        "# Overview\n",
        "This notebook generates the estimated affinity values  (and corresponding summary plots) for experimental seeds (Figure 3A) and different walking strategies (Figure 3B)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "fMEeBFEHjYga"
      },
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "import pandas as pd    \n",
        "import plotnine as p9"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "36xx8bp4T8Df"
      },
      "source": [
        "# Parameters used in manuscript"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "HlfJSFtKV3VH"
      },
      "outputs": [],
      "source": [
        "# Fraction of expected bead coverage from sequencing to consider non-contamination\n",
        "# For example, a tolerated bead fraction of 0.2 means that if, based on read \n",
        "# depth and number of beads, there are 100 reads expected per bead, then \n",
        "# sequences with fewer than 20 reads would be excluded from analysis.\n",
        "TOLERATED_BEAD_FRAC = 0.2 \n",
        "\n",
        "# Ratio cutoff between positive and negative pools to count as being real.\n",
        "# The ratio is calculated normalized by read depth, so if the ratio is 0.5, \n",
        "# then positive sequences are expected to have equal read depth (or more) in \n",
        "# the positive pool as the negative pool. So, as a toy example, if the \n",
        "# positive pool had 100 reads total and the negative pool had 200 reads total,\n",
        "# then a sequence with 5 reads in the positive pool and 10 reads in the \n",
        "# negative pool would have a ratio of 0.5.\n",
        "POS_NEG_RATIO_CUTOFF = 0.5\n",
        "\n",
        "# Minimum required reads (when 0 it uses only the above filters)\n",
        "MIN_READ_THRESH = 0"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 173
        },
        "executionInfo": {
          "elapsed": 481,
          "status": "ok",
          "timestamp": 1603474417220,
          "user": {
            "displayName": "Ali Bashir",
            "userId": "01976351517997791084"
          },
          "user_tz": 420
        },
        "id": "EaDYmK8MTNQ2",
        "outputId": "710708e4-5cc6-4644-c330-7edcec823a13"
      },
      "outputs": [
        {
          "data": {
            "text/html": [
              "\u003cdiv\u003e\n",
              "\u003cstyle scoped\u003e\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "\u003c/style\u003e\n",
              "\u003ctable border=\"1\" class=\"dataframe\"\u003e\n",
              "  \u003cthead\u003e\n",
              "    \u003ctr style=\"text-align: right;\"\u003e\n",
              "      \u003cth\u003e\u003c/th\u003e\n",
              "      \u003cth\u003eapt_collected\u003c/th\u003e\n",
              "      \u003cth\u003eapt_screened\u003c/th\u003e\n",
              "      \u003cth\u003econdition\u003c/th\u003e\n",
              "      \u003cth\u003econdition_flag\u003c/th\u003e\n",
              "      \u003cth\u003eseq_input\u003c/th\u003e\n",
              "      \u003cth\u003estringency\u003c/th\u003e\n",
              "    \u003c/tr\u003e\n",
              "  \u003c/thead\u003e\n",
              "  \u003ctbody\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth\u003e0\u003c/th\u003e\n",
              "      \u003ctd\u003e12204\u003c/td\u003e\n",
              "      \u003ctd\u003e3283890.016\u003c/td\u003e\n",
              "      \u003ctd\u003eround1_very_positive\u003c/td\u003e\n",
              "      \u003ctd\u003eround1_very_flag\u003c/td\u003e\n",
              "      \u003ctd\u003e200000\u003c/td\u003e\n",
              "      \u003ctd\u003eVery High\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth\u003e1\u003c/th\u003e\n",
              "      \u003ctd\u003e50353\u003c/td\u003e\n",
              "      \u003ctd\u003e6628573.952\u003c/td\u003e\n",
              "      \u003ctd\u003eround1_high_positive\u003c/td\u003e\n",
              "      \u003ctd\u003eround1_high_flag\u003c/td\u003e\n",
              "      \u003ctd\u003e200000\u003c/td\u003e\n",
              "      \u003ctd\u003eHigh\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth\u003e2\u003c/th\u003e\n",
              "      \u003ctd\u003e153845\u003c/td\u003e\n",
              "      \u003ctd\u003e5801469.696\u003c/td\u003e\n",
              "      \u003ctd\u003eround1_medium_positive\u003c/td\u003e\n",
              "      \u003ctd\u003eround1_medium_flag\u003c/td\u003e\n",
              "      \u003ctd\u003e200000\u003c/td\u003e\n",
              "      \u003ctd\u003eMedium\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "    \u003ctr\u003e\n",
              "      \u003cth\u003e3\u003c/th\u003e\n",
              "      \u003ctd\u003e201255\u003c/td\u003e\n",
              "      \u003ctd\u003e3508412.512\u003c/td\u003e\n",
              "      \u003ctd\u003eround1_low_positive\u003c/td\u003e\n",
              "      \u003ctd\u003eround1_low_flag\u003c/td\u003e\n",
              "      \u003ctd\u003e200000\u003c/td\u003e\n",
              "      \u003ctd\u003eLow\u003c/td\u003e\n",
              "    \u003c/tr\u003e\n",
              "  \u003c/tbody\u003e\n",
              "\u003c/table\u003e\n",
              "\u003c/div\u003e"
            ],
            "text/plain": [
              "   apt_collected  apt_screened               condition      condition_flag  \\\n",
              "0          12204   3283890.016    round1_very_positive    round1_very_flag   \n",
              "1          50353   6628573.952    round1_high_positive    round1_high_flag   \n",
              "2         153845   5801469.696  round1_medium_positive  round1_medium_flag   \n",
              "3         201255   3508412.512     round1_low_positive     round1_low_flag   \n",
              "\n",
              "   seq_input stringency  \n",
              "0     200000  Very High  \n",
              "1     200000       High  \n",
              "2     200000     Medium  \n",
              "3     200000        Low  "
            ]
          },
          "execution_count": 20,
          "metadata": {
            "tags": []
          },
          "output_type": "execute_result"
        }
      ],
      "source": [
        "#@title MLPD Data Parameters\n",
        "apt_screened_list = [ 3283890.016, 6628573.952, 5801469.696, 3508412.512]\n",
        "apt_collected_list = [12204, 50353, 153845, 201255]\n",
        "seq_input = [200000] * 4\n",
        "conditions = ['round1_very_positive', \n",
        "              'round1_high_positive',\n",
        "              'round1_medium_positive',\n",
        "              'round1_low_positive']\n",
        "flags = ['round1_very_flag', 'round1_high_flag', 'round1_medium_flag', \n",
        "         'round1_low_flag']\n",
        "stringency = ['Very High', 'High', 'Medium', 'Low']\n",
        "mlpd_param_df = pd.DataFrame.from_dict({'apt_screened': apt_screened_list,\n",
        "                                    'apt_collected': apt_collected_list,\n",
        "                                    'seq_input': seq_input,\n",
        "                                    'condition': conditions,\n",
        "                                    'condition_flag': flags,\n",
        "                                    'stringency': stringency})\n",
        "\n",
        "\n",
        "mlpd_param_df"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "WV-un-_QV7LN"
      },
      "source": [
        "# Load in Data"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "3yld_1S-4Fq8"
      },
      "outputs": [],
      "source": [
        "# MLPD sequences with stringency / Kd\n",
        "# Upload mlpd_input_data_manuscript.csv\n",
        "from google.colab import files\n",
        "\n",
        "uploaded = files.upload()\n",
        "\n",
        "for fn in uploaded.keys():\n",
        "  print('User uploaded file \"{name}\" with length {length} bytes'.format(\n",
        "      name=fn, length=len(uploaded[fn])))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "hnEaxJf-YBn5"
      },
      "outputs": [],
      "source": [
        "with open('mlpd_input_data_manuscript.csv') as f:\n",
        "  mlpd_df = pd.read_csv(f)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1HIhJhIKUNJc"
      },
      "source": [
        "# Helper functions"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "tlk4Ur-4Mgjn"
      },
      "outputs": [],
      "source": [
        "def generate_cutoffs_via_PD_stats(df, col, apt_screened, apt_collected, seq_input,\n",
        "                                  tolerated_bead_frac, min_read_thresh):\n",
        "  \"\"\"Use the experimental parameters to determine sequences passing thresholds.\n",
        "\n",
        "  Args:\n",
        "    df: Pandas dataframe with experiment results. Must have columns named \n",
        "      after the col function parameter, containing the read count, and a\n",
        "      column 'sequence'.\n",
        "    col: The string name of the column in the experiment dataframe with the \n",
        "      read count.\n",
        "    apt_screened: The integer number of aptamers screened, from the experiment \n",
        "      parameters.\n",
        "    apt_collected: The integer number of aptamers collected, from the experiment\n",
        "      parameters.\n",
        "    seq_input: The integer number of unique sequences in the sequence library \n",
        "      used to construct the aptamer particles.\n",
        "    tolerated_bead_frac: The float tolerated bead fraction threshold. In other\n",
        "      words, the sequencing depth required to keep a sequence, in units of\n",
        "      fractions of a bead based on the average expected read depth per bead. \n",
        "    min_read_threshold: The integer minimum number of reads that a sequence\n",
        "      must have in order not to be filtered.\n",
        "\n",
        "  Returns:\n",
        "    Pandas series of the sequences from the dataframe that pass filter.\n",
        "  \"\"\"\n",
        "\n",
        "  expected_bead_coverage =  apt_screened / seq_input\n",
        "  tolerated_bead_coverage = expected_bead_coverage * tolerated_bead_frac\n",
        "  bead_full_min_sequence_coverage = (1. / apt_collected) * tolerated_bead_coverage\n",
        "  col_sum = df[col].sum()\n",
        "  # Look at sequenced counts calculated observed fraction of pool and raw count.\n",
        "  seqs = df[((df[col]/col_sum) \u003e bead_full_min_sequence_coverage) \u0026 # Pool frac.\n",
        "            (df[col] \u003e min_read_thresh)   # Raw count\n",
        "            ].sequence\n",
        "  return seqs\n",
        "\n",
        "\n",
        "def generate_pos_neg_normalized_ratio(df, col_prefix):\n",
        "  \"\"\"Adds fraction columns to the dataframe with the calculated pos/neg ratio.\n",
        "\n",
        "  Args:\n",
        "    df: Pandas dataframe, expected to have columns [col_prefix]_positive and\n",
        "      [col_prefix]_negative contain read counts for the positive and negative\n",
        "      selection conditions, respectively.\n",
        "    col_prefix: String prefix of the columns to use to calculate the ratio. \n",
        "      For example 'round1_very_positive'.\n",
        "  \n",
        "  Returns:\n",
        "    The original dataframe with three new columns:\n",
        "    [col_prefix]_positive_frac contains the fraction of the total positive \n",
        "      pool that is this sequence.\n",
        "    [col_prefix]_negative_frac contains the fraction of the total negative\n",
        "      pool that is this sequence.\n",
        "    [col_prefix]_pos_neg_ratio: The read-depth normalized fraction of the \n",
        "      sequence that ended in the positive pool.\n",
        "  \"\"\"\n",
        "  col_pos = col_prefix + '_' + 'positive'\n",
        "  col_neg = col_prefix + '_' + 'negative'\n",
        "  df[col_pos + '_frac'] = df[col_pos] /  df[col_pos].sum()\n",
        "  df[col_neg + '_frac'] = df[col_neg] /  df[col_neg].sum()\n",
        "  df[col_prefix + '_pos_neg_ratio'] = df[col_pos + '_frac'] / (\n",
        "      df[col_pos + '_frac'] + df[col_neg + '_frac'])\n",
        "  return df\n",
        "\n",
        "\n",
        "def build_seq_sets_from_df (input_param_df, input_df, tolerated_bead_frac, \n",
        "                            pos_neg_ratio, min_read_thresh):\n",
        "  \"\"\"Sets flags for sequences based on whether they clear stringencies.\n",
        "\n",
        "  This function adds a column 'seq_set' to the input_param_df (one row per\n",
        "  stringency level of a particle display experiment) containing all the \n",
        "  sequences in the experiment that passed that stringency level in the \n",
        "  experiment.\n",
        "\n",
        "  Args:\n",
        "    input_param_df: Pandas dataframe with experimental parameters. Expected\n",
        "      to have one row per stringency level in the experiment and \n",
        "      columns 'apt_screened', 'apt_collected', 'seq_input', 'condition', and\n",
        "      'condition_flag'.\n",
        "    input_df: Pandas dataframe with the experimental results (counts per \n",
        "      sequence) for the experiment covered in the input_param_df. Expected\n",
        "      to have a [col_prefix]_pos_neg_ratio column for each row of the\n",
        "      input_param_df (i.e. each stringency level).\n",
        "    tolerated_bead_frac: Float representing the minimum sequence depth, in\n",
        "      units of expected beads, for a sequence to be used in analysis.\n",
        "    pos_neg_ratio: The threshold for the pos_neg_ratio column for a sequence\n",
        "      to be used in the analysis.\n",
        "    min_read_thresh: The integer minimum number of reads for a sequence to\n",
        "      be used in the analysis (not normalized, a straight count.)\n",
        "\n",
        "  Returns:\n",
        "    Nothing.\n",
        "\n",
        "  \"\"\"\n",
        "  for _, row in input_param_df.iterrows():\n",
        "    \n",
        "    # Get parameters to calculate bead fraction.\n",
        "    apt_screened = row['apt_screened']\n",
        "    apt_collected = row['apt_collected']\n",
        "    seq_input = row['seq_input']\n",
        "    condition = row['condition']\n",
        "    flag = row['condition_flag']\n",
        "    \n",
        "    # Get sequences above tolerated_bead_frac in positive pool.\n",
        "    tolerated_bead_frac_seqs = generate_cutoffs_via_PD_stats(\n",
        "        input_df, condition, apt_screened, apt_collected, seq_input, \n",
        "        tolerated_bead_frac, min_read_thresh)\n",
        "    \n",
        "    # Intersect with seqs \u003e normalized positive sequencing count ratio.\n",
        "    condition_pre = condition.split('_positive')[0]\n",
        "    ratio_col = '%s_pos_neg_ratio' % (condition_pre)\n",
        "    pos_frac_seqs = input_df[input_df[ratio_col] \u003e pos_neg_ratio].sequence\n",
        "    seqs = set(tolerated_bead_frac_seqs) \u0026 set(pos_frac_seqs)\n",
        "    input_df[flag] = input_df.sequence.isin(set(seqs))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ma9xR2ZUW4X6"
      },
      "source": [
        "## Affnity Helper Function"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "A22ZQ31qW7mw"
      },
      "outputs": [],
      "source": [
        "def set_stringency_level_mlpd (row):\n",
        "  \"\"\"Returns the highest bin for MLPD.\n",
        "\n",
        "  Args:\n",
        "    row: A row from the MLPD experiment results. Expected\n",
        "      to have columns: 'round1_very_flag', \n",
        "      'round1_high_flag', 'round1_medium_flag', 'round1_low_flag' indicating\n",
        "      whether the sequence has passed the stringency threshold for each of\n",
        "      those conditions.\n",
        "\n",
        "  Returns:\n",
        "    Integer from 0-4 indicating the highest stringency level passed by this\n",
        "    sequence, or -1 to indicate conflicting information (for example passing\n",
        "    the high stringency threshold but missing the medium stringency \n",
        "    threshold).\n",
        "  \"\"\"\n",
        "  v_flag = row.round1_very_flag\n",
        "  h_flag = row.round1_high_flag\n",
        "  m_flag = row.round1_medium_flag\n",
        "  l_flag = row.round1_low_flag\n",
        "\n",
        "  if v_flag and h_flag and m_flag and l_flag:\n",
        "    return 4\n",
        "  elif h_flag and m_flag and l_flag and not v_flag:\n",
        "    return 3\n",
        "  elif m_flag and l_flag and not v_flag and not h_flag:\n",
        "    return 2\n",
        "  elif not m_flag and l_flag and not v_flag and not h_flag:\n",
        "    return 1\n",
        "  elif not m_flag and not l_flag and not v_flag and not h_flag:\n",
        "    return 0\n",
        "  else:\n",
        "    return -1"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "G7b_H0eiMXil"
      },
      "source": [
        "## Stacked Bar Plot Helpers"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "BIw_GOSH4VRT"
      },
      "outputs": [],
      "source": [
        "def make_stacked_boxplot(categories, models, stringency_levels, counts, fractions, y='fraction'):\n",
        "  \"\"\"Creates the stacked barplot showing relative enrichment.\n",
        "\n",
        "  The values of categories, models, stringency_levels, counts, and fractions\n",
        "  are the parallel lists created using construct_category_fractions_for_stacked_hists.\n",
        "  Each position in the list represents one segment of the stacked bar chart,\n",
        "  for example, the sequences that started from random seeds, were walked \n",
        "  with the Count model and have stringency_level 3 (=high, Kd \u003c 32nM). \n",
        "\n",
        "  Args:\n",
        "    categories: String list of seed categories, corresponding to the three grey\n",
        "      shaded areas. These are one of 'Random Seeds', 'Expt. Seeds' and \n",
        "      'ML Seeds'.\n",
        "    models: String list of models used to walk the seeds. These represent the\n",
        "      bars within each seed category, i.e. 'Random', 'Counts', 'SuperBin',\n",
        "      'Binned'.\n",
        "    stringency_levels: Integer list of stringency levels, 0-4, representing\n",
        "      Kd levels.\n",
        "    counts: Integer list of the number of sequences in this group of sequences.\n",
        "    fractions: Float list of the fraction of sequences in this group out of\n",
        "      the total sequences at all stringency levels. (For example, the fraction\n",
        "      of sequences from Random Seeds walked by the Counts model that are at\n",
        "      stringency level 2 as a fraction of all the sequences generated by taking\n",
        "      Random Seeds and walking them with the Counts model.)\n",
        "    y: The string name of the column to plot on the y axis.\n",
        "\n",
        "  Returns:\n",
        "    p: the ggplot figure\n",
        "    fishplot_df: The Pandas dataframe with the calculated values.\n",
        "  \"\"\"\n",
        "  fishplot_df = pd.DataFrame.from_dict({'category': categories,\n",
        "                                      'walking_model': models,\n",
        "                                      'stringency_level': stringency_levels,\n",
        "                                      'count': counts, \n",
        "                                      'fraction': fractions})\n",
        "  fishplot_df['log_count'] = np.log2(fishplot_df['count'])\n",
        "  fishplot_df['log_fraction'] = np.log10(fishplot_df['fraction'])\n",
        "  fishplot_df['category_cat'] = pd.Categorical(fishplot_df['category'], \n",
        "                                      categories=['Random Seeds', 'ML Seeds', 'Expt. Seeds'][::-1], \n",
        "                                      ordered=True)\n",
        "  fishplot_df['model_cat'] = pd.Categorical(fishplot_df['walking_model'], \n",
        "                                      categories=['SuperBin',\n",
        "                                                  'Binned', \n",
        "                                                  'Counts', \n",
        "                                                  'Random'][::-1], \n",
        "                                      ordered=True)\n",
        "  def stringency_to_kd(val):\n",
        "    super_bin_to_kd_map = dict(zip(range(5), \n",
        "                                 ['\u003e 512nM', '\u003c 512 nM', '\u003c 128 nM', \n",
        "                                  '\u003c 32 nM', '\u003c 8 nM']))\n",
        "    return super_bin_to_kd_map[val]\n",
        "  \n",
        "  # For plotting skip the aptamers which did not pass any stringency values\n",
        "  fishplot_df = fishplot_df[fishplot_df.stringency_level \u003e 0]\n",
        "  fishplot_df['$K_d$'] = fishplot_df['stringency_level'].apply(stringency_to_kd)\n",
        "  fishplot_df['$K_d$'] = pd.Categorical(\n",
        "      fishplot_df['$K_d$'], \n",
        "      categories=['\u003c 512 nM', '\u003c 128 nM', '\u003c 32 nM', '\u003c 8 nM'], ordered=True)\n",
        "  p = (p9.ggplot(fishplot_df, \n",
        "                 p9.aes(x='model_cat', y=y, alpha='$K_d$', fill='model_cat'))  + \n",
        "       p9.geom_col(position='stack', fill='#32CD32') + p9.coord_flip() + \n",
        "       p9.facet_grid(['category_cat', '.']) + \n",
        "       p9.theme_minimal() + \n",
        "       p9.theme(axis_text_x=p9.element_text(rotation=90, hjust=1), \n",
        "                figure_size=[5, 5], line=p9.element_line(color='white'))) \n",
        "\n",
        "  p = (p9.ggplot(fishplot_df, \n",
        "                 p9.aes(x='model_cat', y=y, alpha='$K_d$', fill='model_cat'))  + \n",
        "       p9.geom_col(position='stack') + p9.coord_flip() + \n",
        "       p9.facet_grid(['category_cat', '.']) + \n",
        "       p9.theme(axis_text_x=p9.element_text(rotation=90, hjust=1), \n",
        "                figure_size=[5, 5], line=p9.element_line(color='white'))  +\n",
        "       p9.scale_fill_manual(['#202124', '#174ea6', '#e37400', '#681da8', '#018774'][::-1]) +\n",
        "       p9.ylim([0.0, 0.2])\n",
        "  )\n",
        "  return p, fishplot_df"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Rv7zrnhDf6rw"
      },
      "outputs": [],
      "source": [
        "def construct_category_fractions_for_stacked_hists (\n",
        "    input_df, col, col_cat, cat_label, groupby_col, base_model,\n",
        "    categories, models, stringency_levels, counts, fractions, base_models \n",
        "    ):\n",
        "  '''For each subcategory calculate the fraction of data at each Kd.\n",
        "\n",
        "  This function adds to the parallel lists of categories, models, \n",
        "  stringency_levels, counts, fractions, and base_models that are later used\n",
        "  in creating the stacked bar plots.\n",
        "\n",
        "  For example, col_cat=['RANDOM_SEEDS_WALKED'], col='sequence_set', \n",
        "  col_label='Random Seeds', groupby_col='walking_model', and base_model=None\n",
        "  would limit the input dataframe of sequences to those sequences where the\n",
        "  sequence set is 'RANDOM_SEEDS_WALKED' (in other words, the set of sequences\n",
        "  that started from random sequences and were walked by an ML model). These\n",
        "  sequences would then by grouped by the walking model column plus the\n",
        "  stringency level (i.e. 0-4), i.e. the  model used to walk these sequences \n",
        "  and the affinity of the resulting sequence. For each group, the results\n",
        "  would be added to each of these parallel lists. So in this case, the \n",
        "  category would always be 'Random Seeds' (since that's the col_label), \n",
        "  and the model would be the walking model, and the stringency level would\n",
        "  be the stringency level of the group. So far this is all basic categories.\n",
        "  The next lists are the actual values used in plotting. The number of sequences\n",
        "  in the group gets added to the counts list, and the number of sequences in\n",
        "  this group relative to all those in this groupby_col is added to the fractions\n",
        "  list (in other words, what is the  fraction of random seeds walked by the \n",
        "  Counts model that ended up at stringency level 2 compared to all the sequences\n",
        "  generated by walking all random seeds with the Counts model.)\n",
        "\n",
        "  Args:\n",
        "    input_df: (pd.DataFrame) Dataframe for grouping.\n",
        "    cols: (str) Column id to select when subsetting dataframe.\n",
        "    col_cat: (list) Category within col to match when subsetting.\n",
        "    cat_label: (str) New label to call category.\n",
        "    groupby_col: (str) Column idea to group remaining subgroup on.\n",
        "    base_model: (str or None) Optional base model.  Not currently being used.\n",
        "    categories: (list) List of categories to append to.\n",
        "    models: (list) List of models to append to.\n",
        "    stringency_levels: (list) List of upated_super_bins to append to.\n",
        "    counts: (list) List of counts to append to.\n",
        "    fractions: (list) List of fractions to append to.\n",
        "    base_models: (list) List of base_models to append to.\n",
        "  '''\n",
        "  # Select out all unambiguous sequences in this set\n",
        "  sub_df = input_df[(input_df[col].isin(col_cat)) \u0026 \n",
        "                    (input_df.stringency_level \u003e= 0)]\n",
        "\n",
        "  # Create summary stats by stringency level\n",
        "  for (groupby_cat, stringency), grp in sub_df.groupby([groupby_col, \n",
        "                                                       'stringency_level']):\n",
        "    categories.append(cat_label)\n",
        "    models.append(groupby_cat)\n",
        "    stringency_levels.append(stringency)  \n",
        "    counts.append(len(grp))\n",
        "    denominator = len(sub_df[(sub_df[col].isin(col_cat)) \u0026\n",
        "                            (sub_df[groupby_col] == groupby_cat)])\n",
        "    fractions.append(float(len(grp)) / denominator)\n",
        "    base_models.append(base_model)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "IMIgaitGGjP5"
      },
      "source": [
        "# Convert stringencies to Kd"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "edlWLAAuWO6i"
      },
      "outputs": [],
      "source": [
        "#@title Add positive_frac / (positive_frac + negative_frac) col to df\n",
        "\n",
        "for col_prefix in ['round1_very', 'round1_high', 'round1_medium', 'round1_low']:\n",
        "  mlpd_df = generate_pos_neg_normalized_ratio(mlpd_df, col_prefix)\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "PqTgkMJKWbdJ"
      },
      "outputs": [],
      "source": [
        "#@title Measure consistency of particle display data when increasing stringency thresholds and set stringeny levels\n",
        "build_seq_sets_from_df (mlpd_param_df, mlpd_df, \n",
        "                        TOLERATED_BEAD_FRAC, \n",
        "                        POS_NEG_RATIO_CUTOFF, MIN_READ_THRESH)\n",
        "mlpd_df['stringency_level'] = mlpd_df.apply(\n",
        "    lambda x: set_stringency_level_mlpd(x), axis=1)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Y6COfPyyQIoi"
      },
      "source": [
        "## Special Handling of 25 sequences ordered at higher multiplicity\n",
        "\n",
        "The particle display experiment requires a minimum amount of positive material for sequencing to succeed. (Otherwise it's easy to lose the pellet during PCR steps, for example.)\n",
        "\n",
        "We did not know a priori if we would meet this minimum level from our generated aptamers, therefore we spiked in a set of 25 sequences at higher copy number (400-fold) that were known/expected to be very good aptamers.  Here, we refine affinity estimates for these 25 sequences due to this increase in input copy number."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "executionInfo": {
          "elapsed": 10527,
          "status": "ok",
          "timestamp": 1603474432810,
          "user": {
            "displayName": "Ali Bashir",
            "photoUrl": "https://lh3.googleusercontent.com/a-/AOh14Gg_2QzdOhvL03-igIA8CW4RWncTEV4gLZ80ECLPkg=s64",
            "userId": "01976351517997791084"
          },
          "user_tz": 420
        },
        "id": "FCuyNxTQG-HF",
        "outputId": "ead59f3b-9f5f-46a3-afdb-5446736199d0"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Mean fold increase over library:  356.2413143113234\n",
            "Median fold increase over library:  405.75\n"
          ]
        }
      ],
      "source": [
        "# First create 2 dataframes for the 25 and everything else\n",
        "mlpd_high_count_df = mlpd_df[mlpd_df['multiple_copy_oligo_in_library']].copy()\n",
        "mlpd_nonhigh_count_df = mlpd_df[~mlpd_df['multiple_copy_oligo_in_library']]\n",
        "\n",
        "# Confirm that observed high count library is 400 fold greater than rest of library\n",
        "print \"Mean fold increase over library: \", mlpd_high_count_df.library.mean() / mlpd_nonhigh_count_df.library.mean()\n",
        "print \"Median fold increase over library: \", mlpd_high_count_df.library.median() / mlpd_nonhigh_count_df.library.median()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "bMvoZg__Swn8"
      },
      "outputs": [],
      "source": [
        "# Multiply tolerated bead frac by the 400 copies ordered in the library\n",
        "build_seq_sets_from_df (mlpd_param_df, mlpd_high_count_df, \n",
        "                        TOLERATED_BEAD_FRAC*400, \n",
        "                        POS_NEG_RATIO_CUTOFF, MIN_READ_THRESH)\n",
        "mlpd_high_count_df['stringency_level'] = mlpd_high_count_df.apply(\n",
        "    lambda x: set_stringency_level_mlpd(x), axis=1)\n",
        "# Join the two sublibraries back together\n",
        "mlpd_df = pd.concat([mlpd_high_count_df, mlpd_nonhigh_count_df])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "4533EXRRifVL"
      },
      "source": [
        "## Set stringency levels to rough kd thresholds\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "-asTw_FzHLSH"
      },
      "outputs": [],
      "source": [
        "mlpd_stringency_to_kd_map = dict(zip(\n",
        "    range(-1, 5), \n",
        "    ['ambiguous', '\u003e 512nM', '\u003c 512 nM', '\u003c 128 nM', '\u003c 32 nM', '\u003c 8 nM']))\n",
        "\n",
        "mlpd_df['Kd'] = mlpd_df.stringency_level.apply(\n",
        "    lambda x: mlpd_stringency_to_kd_map[x])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ewCE7ITr2t9t"
      },
      "source": [
        "# Build plot components by adding in walks from random, experimental, and ML seeds "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "2LI4_ly3kXHZ"
      },
      "outputs": [],
      "source": [
        "categories = []\n",
        "models = []\n",
        "stringency_levels = []\n",
        "counts = []\n",
        "fractions = []\n",
        "base_models = []\n",
        "\n",
        "construct_category_fractions_for_stacked_hists(\n",
        "    mlpd_df, 'sequence_set', ['RANDOM_SEEDS_WALKED'], 'Random Seeds', 'walking_model', None,\n",
        "    categories, models, stringency_levels, counts, fractions, base_models)\n",
        "\n",
        "construct_category_fractions_for_stacked_hists(\n",
        "    mlpd_df, 'sequence_set', ['EXPT_SEEDS_WALKED'], 'Expt. Seeds', 'walking_model', None,\n",
        "    categories, models, stringency_levels, counts, fractions, base_models)\n",
        "\n",
        "construct_category_fractions_for_stacked_hists(\n",
        "    mlpd_df, 'sequence_set', ['MODEL_INFERENCE_WALKED'], 'ML Seeds', 'walking_model', None,\n",
        "    categories, models, stringency_levels, counts, fractions, base_models)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "HpHmHmGmGw3R"
      },
      "source": [
        "# Generate Figure Data/Plots"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "executionInfo": {
          "elapsed": 10242,
          "status": "ok",
          "timestamp": 1603474433492,
          "user": {
            "displayName": "Ali Bashir",
            "photoUrl": "https://lh3.googleusercontent.com/a-/AOh14Gg_2QzdOhvL03-igIA8CW4RWncTEV4gLZ80ECLPkg=s64",
            "userId": "01976351517997791084"
          },
          "user_tz": 420
        },
        "id": "eyz1Ttd8bCDt",
        "outputId": "00a1b62b-7726-4f69-ace5-7e6539936060"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Total sequences observed in MLPD sequencing :  398\n"
          ]
        }
      ],
      "source": [
        "# Only 398 of the 400 expt seed sequences were observed in the sequencing data\n",
        "print 'Total sequences observed in MLPD sequencing : ', mlpd_df[mlpd_df['sequence_set'] == 'EXPT_SEEDS'].Kd.value_counts().sum()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "executionInfo": {
          "elapsed": 10023,
          "status": "ok",
          "timestamp": 1603474433742,
          "user": {
            "displayName": "Ali Bashir",
            "photoUrl": "https://lh3.googleusercontent.com/a-/AOh14Gg_2QzdOhvL03-igIA8CW4RWncTEV4gLZ80ECLPkg=s64",
            "userId": "01976351517997791084"
          },
          "user_tz": 420
        },
        "id": "rFbHUqubYuec",
        "outputId": "87a38122-6940-465b-ac6c-fdd1af68d2b3"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "\u003c 512 nM     150\n",
              "\u003e 512nM      123\n",
              "\u003c 128 nM     102\n",
              "ambiguous     13\n",
              "\u003c 32 nM        8\n",
              "\u003c 8 nM         4\n",
              "Name: Kd, dtype: int64"
            ]
          },
          "execution_count": 33,
          "metadata": {
            "tags": []
          },
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Extracting remaining 2 seeds from walks and set values to ambiguous (same as conflicting seeds in stringency map)\n",
        "expt_seeds = mlpd_df[mlpd_df.sequence_set == 'EXPT_SEEDS_WALKED'].seed_seq.unique()\n",
        "expt_seed_df = pd.DataFrame.from_dict({'sequence': expt_seeds})\n",
        "mlpd_seed_df = expt_seed_df.merge(mlpd_df, on='sequence', how='left')\n",
        "mlpd_seed_df['Kd'].fillna('ambiguous', inplace=True)\n",
        "mlpd_seed_df.Kd.value_counts()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 496
        },
        "executionInfo": {
          "elapsed": 9768,
          "status": "ok",
          "timestamp": 1603474434763,
          "user": {
            "displayName": "Ali Bashir",
            "photoUrl": "https://lh3.googleusercontent.com/a-/AOh14Gg_2QzdOhvL03-igIA8CW4RWncTEV4gLZ80ECLPkg=s64",
            "userId": "01976351517997791084"
          },
          "user_tz": 420
        },
        "id": "XO4UqaG4bIDt",
        "outputId": "edc03d54-8991-4353-f6d1-7e36d39840ad"
      },
      "outputs": [
        {
          "data": {
            "image/png": "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\n",
            "text/plain": [
              "\u003cFigure size 500x500 with 3 Axes\u003e"
            ]
          },
          "metadata": {
            "tags": []
          },
          "output_type": "display_data"
        },
        {
          "data": {
            "text/plain": [
              "\u003cggplot: (8787739034497)\u003e"
            ]
          },
          "execution_count": 34,
          "metadata": {
            "tags": []
          },
          "output_type": "execute_result"
        }
      ],
      "source": [
        "#3B\n",
        "p, fishplot_df = make_stacked_boxplot(\n",
        "    categories, models, stringency_levels, counts, fractions, y='fraction')\n",
        "p"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [],
      "last_runtime": {
        "build_target": "//research/biology/collaborations/aptamers:notebook",
        "kind": "shared"
      },
      "name": "Figure 3 Machine-learning-guided aptamer discovery (submission).ipynb",
      "provenance": [
        {
          "file_id": "1lnOjQL0n22MTkqWu5-muLaQ2n9D3IgsS",
          "timestamp": 1603475243607
        },
        {
          "file_id": "1Yr-U-1Au7aHDgdMhzI3V2ne5Ngc_Yq_0",
          "timestamp": 1603474804395
        },
        {
          "file_id": "1bCY27-701njNFilJR8O53Nk6nDykbiGS",
          "timestamp": 1603356659475
        },
        {
          "file_id": "12lB5W1pqRAusjFBehBcIB-rUWWEO40Wv",
          "timestamp": 1603356620654
        },
        {
          "file_id": "1HVMBWUAIVH2rLS7L7mJg6nQa7_2e5dqd",
          "timestamp": 1603294928626
        },
        {
          "file_id": "1o1Nzo0DqheofdpUsOcw3Y-yvr7Zfw1fM",
          "timestamp": 1601594445419
        },
        {
          "file_id": "1oW0opjcw801PT2zvAKKow9OnTHcMH1Bo",
          "timestamp": 1592776384405
        },
        {
          "file_id": "11Ltt7PwgJXdNwcYIM2LQPLTA7xhXL7dP",
          "timestamp": 1591825416238
        },
        {
          "file_id": "1y-rDPmrqh-X94iAXHCpo4ThdZBGX5G6f",
          "timestamp": 1590592797191
        },
        {
          "file_id": "1rNoIHfkUvT1oPcvT7dBglQ8a4vos83eL",
          "timestamp": 1586451115413
        },
        {
          "file_id": "1QGwmo4nQzMaD4HrW3dAW59BYOQGCdxw-",
          "timestamp": 1580512194777
        }
      ],
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 2",
      "name": "python2"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
